﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using System.Collections;

namespace Asplode
{
    public class Console
    {
        private static int DEFAULT_MAX_LINES = 10;
        private static int DEFAULT_DISAPPEAR_TIME_MS = 5000;

        public Vector2 position;

        private Color color;
        private SpriteFont font;
        private List<KeyValuePair<String, DateTime>> lines;
        private SpriteBatch spriteBatch;

        public int maxLines;
        public int disappearTimeMs;

        public Console(ContentManager content, SpriteBatch spriteBatch)
        {
            position = new Vector2(20, 20);
            maxLines = DEFAULT_MAX_LINES;
            disappearTimeMs = DEFAULT_DISAPPEAR_TIME_MS;
            this.spriteBatch = spriteBatch;
            font = content.Load<SpriteFont>("Fonts\\ConsoleFont");
            lines = new List<KeyValuePair<String, DateTime>>();
            color = Color.White;
        }

        public void Print(String line)
        {
            // Remove old lines if necessary to make room for this one.
            while (lines.Count >= maxLines)
            {
                lines.RemoveAt(0);
            }

            lines.Add(new KeyValuePair<String, DateTime>(line, DateTime.Now));
        }

        public void Draw()
        {
            // Any lines older than this time will be removed.
            DateTime cutoff = DateTime.Now.AddMilliseconds(-disappearTimeMs);

            while (lines.Count > 0 && lines[0].Value < cutoff)
            {
                lines.RemoveAt(0);
            }

            float xPos = position.X;
            float yPos = position.Y;
            Vector2 printPosition = new Vector2(xPos, yPos);
            foreach (KeyValuePair<String, DateTime> pair in lines)
            {
                spriteBatch.DrawString(font, pair.Key, printPosition, color);
                printPosition.Y += 20;
            }
        }
    }

    public class FPSCounter : Console
    {
        private double sum;

        // Discard any samples older than 500 ms.
        private static int SAMPLE_AGE_LIMIT_MS = 500;

        private class Sample
        {
            public TimeSpan time;
            public int elapsedMs;

            public Sample(TimeSpan time, int elapsedMs)
            {
                this.time = time;
                this.elapsedMs = elapsedMs;
            }

            public bool isExpired(TimeSpan cutoff)
            {
                return time < cutoff;
            }
        }

        private Queue<Sample> samples;

        public FPSCounter(ContentManager content, SpriteBatch spriteBatch)
            :   base(content, spriteBatch)
        {
            samples = new Queue<Sample>();
            maxLines = 1;
            sum = 0;
        }

        public void Update(GameTime gameTime)
        {
            // Remove old samples as necessary.
            TimeSpan cutoff = gameTime.TotalGameTime.Add(new TimeSpan(0, 0, 0, 0, SAMPLE_AGE_LIMIT_MS));

            // Remove old samples.
            while (samples.Count > 0 && samples.Peek().isExpired(cutoff))
            {
                Sample toRemove = samples.Dequeue();
                sum -= toRemove.elapsedMs;
            }

            samples.Enqueue(new Sample(gameTime.TotalGameTime, gameTime.ElapsedGameTime.Milliseconds));
            sum += gameTime.ElapsedGameTime.Milliseconds;

            Print(String.Format("{0:0.0}", (1000 * samples.Count) / sum) + " FPS");
        }
    }
}
